/* [n_adc]
 *********************
 * Things to remember:
 *
 * - detail is threadsafe, use caution, all changes will be seen by all threads; recommend: only use to .get data never .set
 * - global variables are global to all threads, use load & unload to initialize & free up memory
 * - use global isInit to initialize global variables requiring detail to be setup
 * - when using global isInit, the code must be mutex protected so all threads do not run the init, just one
 * - inter-thread coordination can be coordinated via the provided mutex
 */
#include <process.h>
#include <stdio.h>
#include <time.h>

#define DLL_EXPORT
#include "start.h"
#include "Database.h"
#include "Exec.h"
#include "adComputer.h"

#ifdef _WIN32
#ifdef _DEBUG
	#define _CRTDBG_MAP_ALLOC
	#include <stdlib.h>
	#include <crtdbg.h>
	#undef THIS_FILE
	static char THIS_FILE[] = __FILE__;
	#define new       new( _NORMAL_BLOCK, __FILE__, __LINE__)
	#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endif
#endif

#include <iostream>
using namespace std;

#ifdef __cplusplus
extern "C" {
#endif	/*__cplusplus*/


// default global variables within dll
ParamManager *supported = NULL;
// module-specific global variables within dll
bool isInit = false;
Database *db = NULL;
ParamManager *exceptions = NULL;


// called after the module is loaded, useful to load global variables; Returns supported actions as a ParamManager*
DECLDIR ParamManager* load(void) {
	supported = new ParamManager();
	supported->setOverwrite(false);
	supported->set("action", "adc");

	return supported;
//	return "adc;adc_load_stale;adc_load_retired;adc_daily_pending;adc_daily_first_run;adc_daily_active";
}


// called just before the module is unloaded, useful to unload global variables
DECLDIR void unload(void) {
	if(supported) {
		delete supported;
	}
	if(db) {
		delete db;
	}
	if(exceptions) {
		delete exceptions;
	}
}


void init(HANDLE mutex, ParamManager &detail) {
	MYSQL_RES *rUpdate = NULL;

	// ensure we only init once
	if(!isInit) {
		char query[DEFAULT_BUFLEN];

		// Instance Table
		db = new Database(
					detail.get("db_user"), detail.get("db_pass"),
					detail.get("db_name"),
					detail.get("db_host"), atoi(detail.get("db_port")));

/*		// take action db connection failed
		if(&(db->conn) == NULL) {
			return;
		}
*/
		// re-establish mysql connection if lost
		bool connect = true;
		mysql_options(&(db->conn), MYSQL_OPT_RECONNECT, &connect);

		sprintf_s(query, DEFAULT_BUFLEN, "CREATE TABLE IF NOT EXISTS n_adc (");
		strcat_s(query, DEFAULT_BUFLEN, "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY");
		strcat_s(query, DEFAULT_BUFLEN, ", state INT");
		strcat_s(query, DEFAULT_BUFLEN, ", days INT");
		strcat_s(query, DEFAULT_BUFLEN, ", style VARCHAR(256)");
		strcat_s(query, DEFAULT_BUFLEN, ", start_node VARCHAR(256)");
		strcat_s(query, DEFAULT_BUFLEN, ", stale_dn VARCHAR(256)");
		strcat_s(query, DEFAULT_BUFLEN, ", track_id INT");
		strcat_s(query, DEFAULT_BUFLEN, ", hidden BOOL");
		strcat_s(query, DEFAULT_BUFLEN, ")");

		// init is wrapped by mutex, allowing safe mysql call here
		mysql_query(&(db->conn), query);
		rUpdate = mysql_store_result(&(db->conn));
		// free up the result from the mysql query
		mysql_free_result(rUpdate);

		// Exceptions Table
		sprintf_s(query, DEFAULT_BUFLEN, "CREATE TABLE IF NOT EXISTS n_adc_exceptions (");
		strcat_s(query, DEFAULT_BUFLEN, "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY");
		strcat_s(query, DEFAULT_BUFLEN, ", pattern VARCHAR(25)");
		strcat_s(query, DEFAULT_BUFLEN, ", addedBy VARCHAR(25)");
		strcat_s(query, DEFAULT_BUFLEN, ", dt DATETIME");
		strcat_s(query, DEFAULT_BUFLEN, ", days INT");
		strcat_s(query, DEFAULT_BUFLEN, ", note VARCHAR(256)");
		strcat_s(query, DEFAULT_BUFLEN, ", isActive BOOL");
		strcat_s(query, DEFAULT_BUFLEN, ", isElapsed BOOL DEFAULT 0");
		strcat_s(query, DEFAULT_BUFLEN, ")");

		// init is wrapped by mutex, allowing safe mysql call here
		mysql_query(&(db->conn), query);
		rUpdate = mysql_store_result(&(db->conn));
		// free up the result from the mysql query
		mysql_free_result(rUpdate);
		
		// Load up exceptions
		MYSQL_RES *rSelect = NULL;
		MYSQL_ROW row;

		// Obtain list of exceptions
// Implement Exception expiration (ignore expired)
		sprintf(query, "SELECT id, pattern, UNIX_TIMESTAMP(dt), days FROM n_adc_exceptions WHERE isActive=1 AND isElapsed=0");
//		sprintf(query, "SELECT id, pattern, UNIX_TIMESTAMP(dt), days FROM n_adc_exceptions WHERE isActive=1");
		
		// thread-safe mysql call
		rSelect = db->threadsafe_query(mutex, query);

		// Exceptions obtained from database, store them
		exceptions = new ParamManager();
		if(rSelect) {
			while((row = mysql_fetch_row(rSelect))) {
				bool isActive = true;

				// Test - if only active for a certain number of days, has the number of days passed?
				time_t timestamp = strtoul(row[2], NULL, 0);
				int days = atoi(row[3]);
				if(days) {	// ignore 0 days
					struct tm *tm = gmtime(&timestamp);
					tm->tm_mday += days;	// increase the date the number of days

					// have we reached the length of active days?
					timestamp = mktime(tm);
					if(difftime(timestamp, time(NULL)) < 0) {
						// no days remaining, deactivate the exception
						printf("Deactivating exception: '%s', days=%s, missedby=%.0f\n",
								row[1], row[3], ceil(-1 * difftime(timestamp, time(NULL)) / 60 / 60 / 24));

// Implement Exception expiration (expire)
						sprintf(query, "UPDATE n_adc_exceptions SET isActive=0, isElapsed=1 where id=\"%s\"", row[0]);
//						sprintf(query, "UPDATE n_adc_exceptions SET isElapsed=1 where id=\"%s\"", row[0]);
						db->threadsafe_query(mutex, query);
						
						isActive = false;
					}
//					else {
//						printf("Deactivating exception: '%s', days=%s, diff=%f days remaining\n",
//								row[1], row[3], difftime(timestamp, time(NULL)) / 60 / 60 / 24);
//					}
				}
				
				// Otherwise, add to exception list
// Implement Exception expiration (load if not expired)
				if(isActive) {
					exceptions->set(row[1], "");	// exception is the 'name', 'value' will be other details separated with '|' delimited
				}
			}

			// free up the result from the mysql query
			db->safe_mysql_free_result(rSelect);
		}

		isInit = true;
	}
}


DECLDIR void start(HANDLE mutex, ParamManager &detail, char *index) {
	MYSQL_RES *rSelect, *rUpdate;
	MYSQL_ROW row;
	char query[DEFAULT_BUFLEN];
	char netbios[DEFAULT_BUFLEN];
	char dn_curr[DEFAULT_BUFLEN];
	char dn_orig[DEFAULT_BUFLEN];

	// mutex protected init sequence
	WaitForSingleObject(mutex, INFINITE);	// Request ownership of mutex
	init(mutex, detail);					// Init sequence
	ReleaseMutex(mutex);					// Release mutex for other threads
	
/*	// take action db connection failed
	if(&(db->conn) == NULL) {
		printf("mysql_real_connect failed\n");
		// free up mysql thread-specific memory
		mysql_thread_end();
		return;
	}
*/

	// check cmd for action to take
	if(!strcmp(detail.get("action"), "load_stale")) {
		ParamManager dn;
		char cmd[DEFAULT_BUFLEN];

		// Insert a new instance
		sprintf(query, "INSERT INTO n_adc (state, days, style, start_node, stale_dn, track_id) VALUES (%d, %d, \"%s\", \"%s\", \"%s\", %d)",
					0, atoi(detail.get("days")), detail.get("style"), detail.get("start_node"), detail.get("stale_dn"), 0);

		// -- Thread-Safe Mysql call --
		// Request ownership of mutex
		WaitForSingleObject(mutex, INFINITE);
		// Make mysql calls which need Mutex protection
		mysql_query(&(db->conn), query);
		printf("new instance: '%s'\n", query);
		rUpdate = NULL;
		rUpdate = mysql_store_result(&(db->conn));
		// obtain insert id
		int insert_id = mysql_insert_id(&(db->conn));
		// Release the mutex
		ReleaseMutex(mutex);
		if(rUpdate) {
			// free up the result from the mysql query
			mysql_free_result(rUpdate);
		}

		// Create a new table for this new instance
		sprintf(query, "CREATE TABLE IF NOT EXISTS n_adc_%d (", insert_id);
		strcat(query, "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY");
		strcat(query, ", netbios VARCHAR(16)");
		strcat(query, ", dn_orig VARCHAR(256)");
		strcat(query, ", dn_curr VARCHAR(256)");
		strcat(query, ", byException BOOLEAN DEFAULT 0");
		strcat(query, ", byLogon BOOLEAN DEFAULT 0");
		strcat(query, ", byPing BOOLEAN DEFAULT 0");
		strcat(query, ", byEnable BOOLEAN DEFAULT 0");
		strcat(query, ", byMove BOOLEAN DEFAULT 0");
		strcat(query, ", byDelete BOOLEAN DEFAULT 0");
		strcat(query, ", isIgnore BOOLEAN DEFAULT 0");
		strcat(query, ", track_id INT DEFAULT 0");
		strcat(query, ")");

		// thread-safe mysql call
		rUpdate = db->threadsafe_query(mutex, query);
		db->safe_mysql_free_result(rUpdate);

		// Create a new table for this new instance for logging
		sprintf(query, "CREATE TABLE IF NOT EXISTS n_adc_%d_log (", insert_id);
		strcat(query, "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY");
		strcat(query, ", dt DATETIME");
		strcat(query, ", msg VARCHAR(256)");
		strcat(query, ", track_id INT DEFAULT 0");
		strcat(query, ")");

		// thread-safe mysql call
		rUpdate = db->threadsafe_query(mutex, query);
		db->safe_mysql_free_result(rUpdate);

		// dsquery stale objects which are older than specified number of days
		sprintf(cmd, "dsquery computer \"%s\" -name \"*\" -limit 0 -stalepwd %s",
				detail.get("start_node"), detail.get("days"));
//		printf("cmd is '%s'\r\n", cmd);
		char *buffer;
		int count = 0;
		Exec proc(cmd);
		// process output
		if(proc.isOutput()) {
			// get the next line of output
			while(buffer = proc.getNext()) {
				// skip blank lines
				if(strlen(buffer) == 0) {
					continue;
				}
//				printf("> %s", buffer);

				// ignore specific ou
				if(strstr(buffer, "OU=BMC Software")) {
					continue;
				}

				dn.init(buffer, ",");
				sprintf(query, "INSERT INTO n_adc_%d (netbios, dn_curr, dn_orig) VALUES (\"%s\", %s, %s)", insert_id, dn.head->value, buffer, buffer);
//				printf("query='%s'\r\n", query);

				// thread-safe mysql call
				rUpdate = NULL;
				rUpdate = db->threadsafe_query(mutex, query);
				if(rUpdate) {
					// free up the result from the mysql query
					mysql_free_result(rUpdate);
				}
			}
		}
	}
	else if(!strcmp(detail.get("action"), "load_retired")) {
		ParamManager dn;
		char cmd[DEFAULT_BUFLEN];

		// Insert a new instance
		sprintf(query, "INSERT INTO n_adc (state, days, style, start_node, stale_dn, track_id) VALUES (%d, %d, \"%s\", \"%s\", \"%s\", %d)",
					0, atoi(detail.get("days")), detail.get("style"), detail.get("start_node"), detail.get("stale_dn"), 0);

		// -- Thread-Safe Mysql call --
		// Request ownership of mutex
		WaitForSingleObject(mutex, INFINITE);
		// Make mysql calls which need Mutex protection
		mysql_query(&(db->conn), query);
		printf("new instance: '%s'\n", query);
		rUpdate = NULL;
		rUpdate = mysql_store_result(&(db->conn));
		// obtain insert id
		int insert_id = mysql_insert_id(&(db->conn));
		// Release the mutex
		ReleaseMutex(mutex);
		if(rUpdate) {
			// free up the result from the mysql query
			mysql_free_result(rUpdate);
		}

		// Create a new table for this new instance
		sprintf(query, "CREATE TABLE IF NOT EXISTS n_adc_%d (", insert_id);
		strcat(query, "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY");
		strcat(query, ", netbios VARCHAR(16)");
		strcat(query, ", dn_orig VARCHAR(256)");
		strcat(query, ", dn_curr VARCHAR(256)");
		strcat(query, ", byException BOOLEAN DEFAULT 0");
		strcat(query, ", byLogon BOOLEAN DEFAULT 0");
		strcat(query, ", byPing BOOLEAN DEFAULT 0");
		strcat(query, ", byEnable BOOLEAN DEFAULT 0");
		strcat(query, ", byMove BOOLEAN DEFAULT 0");
		strcat(query, ", byDelete BOOLEAN DEFAULT 0");
		strcat(query, ", isIgnore BOOLEAN DEFAULT 0");
		strcat(query, ", track_id INT DEFAULT 0");
		strcat(query, ")");

		// thread-safe mysql call
		rUpdate = NULL;
		rUpdate = db->threadsafe_query(mutex, query);
		if(rUpdate) {
			// free up the result from the mysql query
			mysql_free_result(rUpdate);
		}

		// Create a new table for this new instance for logging
		sprintf(query, "CREATE TABLE IF NOT EXISTS n_adc_%d_log (", insert_id);
		strcat(query, "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY");
		strcat(query, ", dt DATETIME");
		strcat(query, ", msg VARCHAR(256)");
		strcat(query, ", track_id INT DEFAULT 0");
		strcat(query, ")");

		// thread-safe mysql call
		rUpdate = NULL;
		rUpdate = db->threadsafe_query(mutex, query);
		if(rUpdate) {
			// free up the result from the mysql query
			mysql_free_result(rUpdate);
		}

		// dsquery stale objects which are older than specified number of days
		sprintf(cmd, "dsquery computer \"%s\" -name \"*-retired\" -limit 0",
				detail.get("start_node"), detail.get("days"));
//		printf("cmd is '%s'\r\n", cmd);
		char *buffer;
		int count = 0;
		Exec proc_ret(cmd);
		// process output
		if(proc_ret.isOutput()) {
			// get the next line of output
			while(buffer = proc_ret.getNext()) {
				// skip blank lines
				if(strlen(buffer) == 0) {
					continue;
				}
//				printf("> %s", buffer);

				// ignore specific ou
				if(strstr(buffer, "OU=BMC Software") != NULL) {
					continue;
				}

				dn.init(buffer, ",");
				sprintf(query, "INSERT INTO n_adc_%d (netbios, dn_curr, dn_orig) VALUES (\"%s\", %s, %s)", insert_id, dn.head->value, buffer, buffer);
//				printf("query='%s'\r\n", query);

				// thread-safe mysql call
				rUpdate = NULL;
				rUpdate = db->threadsafe_query(mutex, query);
				if(rUpdate) {
					// free up the result from the mysql query
					mysql_free_result(rUpdate);
				}
			}
		}

		// dsquery stale objects which are older than specified number of days
		sprintf(cmd, "dsquery computer \"%s\" -name \"*-old\" -limit 0",
		detail.get("start_node"), detail.get("days"));
//		printf("cmd is '%s'\r\n", cmd);
		
		Exec proc_old(cmd);
		// process output
		if(proc_old.isOutput()) {
			// get the next line of output
			while(buffer = proc_old.getNext()) {
				// skip blank lines
				if(strlen(buffer) == 0) {
					continue;
				}
//				printf("> %s", buffer);

				// ignore specific ou
				if(strstr(buffer, "OU=BMC Software") != NULL) {
					continue;
				}

				dn.init(buffer, ",");
				sprintf(query, "INSERT INTO n_adc_%d (netbios, dn_curr, dn_orig) VALUES (\"%s\", %s, %s)", insert_id, dn.head->value, buffer, buffer);
//				printf("query='%s'\r\n", query);

				// thread-safe mysql call
				rUpdate = NULL;
				rUpdate = db->threadsafe_query(mutex, query);
				if(rUpdate) {
					// free up the result from the mysql query
					mysql_free_result(rUpdate);
				}
			}
		}
	}
	else if(!strcmp(detail.get("action"), "daily")) {
		// Load up the instance
		sprintf(query, "SELECT * FROM n_adc WHERE id=%s", detail.get("instance"));

		// thread-safe mysql call
		rSelect = db->threadsafe_query(mutex, query);

		// save the instance details
		if(rSelect) {
			if((row = mysql_fetch_row(rSelect))) {
				detail.set("state", row[1]);
				detail.set("days", row[2]);
				detail.set("style", row[3]);
				detail.set("start_node", row[4]);
				detail.set("stale_dn", row[5]);
				detail.set("track_id", row[6]);
			}
//			else {
//				// this should never happen
//			}
			
			// free up the result form the mysql query
			db->safe_mysql_free_result(rSelect);
		}

		// Perform database query and display info
//		sprintf(query, "SELECT id, netbios, dn_curr, dn_orig FROM n_adc_%s WHERE id = %d AND isIgnore = 0 AND track_id != %s",
		BIGNUM *tmp = BN_new();
		BN_dec2bn(&tmp, index);
		BN_add_word(tmp, 1);	// increase our id by one, as db tables start at 1 not 0
		char *sindex = BN_bn2dec(tmp);
		BN_free(tmp);
		sprintf_s(query, DEFAULT_BUFLEN, "SELECT id, netbios, dn_curr, dn_orig, isIgnore FROM n_adc_%s WHERE id = %s AND track_id != %s",
					detail.get("instance"), sindex,
					detail.get("track_id"));	// plus 1 cause blocks start w/ 0, but table starts w/ 1
		OPENSSL_free(sindex);
//		printf("daily query = '%s'\n", query);

		// thread-safe mysql call
		rSelect = db->threadsafe_query(mutex, query);

		if(rSelect) {
			while((row = mysql_fetch_row(rSelect))) { 
				sprintf(netbios, "%s", row[1]);
				sprintf(dn_curr, "%s", row[2]);
				sprintf(dn_orig, "%s", row[3]);
//				printf("netbios: '%s'\n", netbios);

				bool isIgnore = atoi(row[4]);
				adComputer pc(mutex, atoi(row[0]), netbios, &detail);
//				printf("state = %s\n", detail.get("state"));


				// Occurs regularly before moving to First Run, and then Active
				if(isIgnore) {
					// do nothing, but we keep this here so that down below
					// the track_id still gets incremented to indicate this
					// item has been processed
				}
				else if(!strcmp(detail.get("state"), "0")) {//"pending"
					// Is this Object listed as an exception?
					// flag as byException, and ignore
					if(pc.isException(exceptions)) {
						printf("%s is exception\r\n", netbios);
						pc.setBool(mutex, "byException", true);
						pc.setBool(mutex, "isIgnore", true);
					}
					
					// Does the Object ping?
					// flag as byPing, and ignore
					else if(pc.isPing()) {
						printf("%s pings\r\n", netbios);
						pc.setBool(mutex, "byPing", true);
						pc.setBool(mutex, "isIgnore", true);
					}

					// Is this Object no longer stale?
					// flag as byLogon, and ignore
					else if(!pc.isStale(atoi(detail.get("days")))) {
						if(!strcmp(detail.get("style"), "stale")) {
							printf("%s is not stale\r\n", netbios);
							pc.setBool(mutex, "byLogon", true);
							pc.setBool(mutex, "isIgnore", true);
						}
					}

					// Is the Object still valid?  (untested, add this?)
/*					else if(!pc.isValid()) {
						// flag as byDelete, and ignore
						printf("%s object was deleted, flagging as isIgnore\r\n", netbios);
						pc.setBool("byDelete", true);
						pc.setBool("isIgnore", true);
						// no enabling or moving, the object was deleted
					}
*/				}
				// Only occurs one time, when moving from Pending -> Active
				else if(!strcmp(detail.get("state"), "1")) {//"first_run"
					// disable objects & move to stale_ou (stale_ou will be deleted after 1 month)
					printf("Action: disable '%s'\n", netbios);
					if(!pc.disable(mutex)) {
						printf("Action: disable failed\n");
					}
					printf("Action: move_to stale_dn: '%s'\n", netbios);
					if(pc.moveTo(mutex, detail.get("stale_dn"))) {
						pc.setString(mutex, "dn_curr", pc.dn_curr);
						
					}
				}
				// The regular daily script after objects have been moved and disabled,
				// watching to re-enabled them if any changes are made by someone else.
				else if(!strcmp(detail.get("state"), "2")) {//"active"
					// Is this Object listed as an exception?
					// flag as byException, and ignore
					if(pc.isException(exceptions)) {
						printf("%s is exception, restoring from stale_dn\r\n", netbios);
						pc.setBool(mutex, "byException", true);
						pc.setBool(mutex, "isIgnore", true);
						printf("Action: enable '%s'\n", netbios);
						pc.enable(mutex);

						char *ptr = strchr(dn_orig, ',');
						ptr++;
						printf("Action: move_to pc.dn_curr: '%s'\n", pc.dn_curr);
						if(pc.moveTo(mutex, ptr)) {
							pc.setString(mutex, "dn_curr", pc.dn_curr);
						}
					}

					// Does the Object ping?
					// flag as byPing, and ignore
					else if(pc.isPing()) {
						printf("%s pings, restoring from stale_dn\r\n", netbios);
						pc.setBool(mutex, "byPing", true);
						pc.setBool(mutex, "isIgnore", true);
						printf("Action: enable '%s'\n", netbios);
						pc.enable(mutex);

						char *ptr = strchr(dn_orig, ',');
						ptr++;
						printf("Action: move_to pc.dn_curr: '%s'\n", pc.dn_curr);
						if(pc.moveTo(mutex, ptr)) {
							pc.setString(mutex, "dn_curr", pc.dn_curr);
						}
					}

					// Is this Object no longer stale?
					// flag as byLogon, and ignore
					else if(!pc.isStale(atoi(detail.get("days")))) {
						if(!strcmp(detail.get("style"), "stale")) {
							printf("%s is not stale, restoring from stale_dn\r\n", netbios);
							pc.setBool(mutex, "byLogon", true);
							pc.setBool(mutex, "isIgnore", true);
							printf("Action: enable '%s'\n", netbios);
							pc.enable(mutex);

							char *ptr = strchr(dn_orig, ',');
							ptr++;						
							printf("Action: move_to ptr: '%s'\n", ptr);
							if(pc.moveTo(mutex, ptr)) {
								printf("Setting dn_curr, but does pc.dn_curr have the new value?\n    ptr: %s\ndn_curr:%s\n", ptr, pc.dn_curr);
								pc.setString(mutex, "dn_curr", pc.dn_curr);
							}
						}
					}

					// Is the Object still valid?
					else if(!pc.isValid()) {
						// flag as byDelete, and ignore
						printf("%s object was deleted, flagging as isIgnore\r\n", netbios);
						pc.setBool(mutex, "byDelete", true);
						pc.setBool(mutex, "isIgnore", true);
						// no enabling or moving, the object was deleted
					}

					// Was the Object enabled (after our first_run disable)?
					// flag as byEnable, and ignore
					else if(pc.isEnabled()) {
						printf("%s was enabled, restoring from stale_dn\r\n", netbios);
						pc.setBool(mutex, "byEnable", true);
						pc.setBool(mutex, "isIgnore", true);
						printf("Action: enable '%s'\n", netbios);
						pc.enable(mutex);

						char *ptr = strchr(dn_orig, ',');
						ptr++;
						printf("Action: move_to ptr: '%s'\n", ptr);
						if(pc.moveTo(mutex, ptr)) {
							printf("Setting dn_curr, but does pc.dn_curr have the new value?\n    ptr: %s\ndn_curr:%s\n", ptr, pc.dn_curr);
							pc.setString(mutex, "dn_curr", pc.dn_curr);
						}
					}

					// Was the Object moved (after our first_run move to the stale_ou)?
					// flag as byMove, and ignore
					else if(pc.wasMoved(mutex)) {
						printf("%s was moved, restoring from stale_dn\r\n", netbios);
						pc.setBool(mutex, "byMove", true);
						pc.setBool(mutex, "isIgnore", true);
						printf("Action: enable '%s'\n", netbios);
						pc.enable(mutex);
						// just reenable, we don't want to move back to original location
						// because whereever the object is now, someone else moved it there
					}
				}
				//
				else if(!strcmp(detail.get("state"), "3")) {//"complete"
					// do nothing
					printf("do nothing\n");
				}

				// update the track_id to indicate this item has been processed
				pc.setString(mutex, "track_id", detail.get("track_id"));
			}

			// free up the result form the mysql query
			mysql_free_result(rSelect);
		}
		else {
			// query failed or, there were no results such as in the case of isIgnore = 1
			printf("[Thread::n_adc] (daily, pending): db query failed\r\n");
		}
	}

	// free up mysql thread-specific memory
	mysql_thread_end();
}


#ifdef __cplusplus
}
#endif	/*__cplusplus */